#-*- coding:utf-8 -*-
import os
import time
import configparser
import json
import traceback
import shutil
import zipfile
import threading
import zmq
from update.tools.w_deployment_send import DEHandler
from git import *
from socketserver import BaseRequestHandler, TCPServer, ThreadingTCPServer


class myconf(configparser.ConfigParser):
    def optionxform(self, optionstr):
        return optionstr
    
    def _write_section(self, fp, section_name, section_items, delimiter):
        """Write a single section to the specified `fp'."""
        fp.write("[{}]\r\n".format(section_name))
        for key, value in section_items:
            value = self._interpolation.before_write(self, section_name, key,
                                                     value)
            if value is not None or not self._allow_no_value:
                value = delimiter + str(value).replace('\n', '\n\t')
            else:
                value = ""
            fp.write("{}{}\r\n".format(key, value).replace(' ',''))
        fp.write("\r\n") 


class deployment_zcell(object):
    def __init__(self):
        #self.context = zmq.Context()
        self.config_file = 'update/tools/config.ini'
        self.config = myconf()
        self.config.read(self.config_file)
        self.Equipment_file = 'update/tools/Equipment.ini'
        self.Equipment = myconf()
        self.Equipment.read(self.Equipment_file)
        self.deployment_file = self.config.get('service_side','deployment_file')
        self.git_file = self.config.get('service_side','git_file')
        self.module_file = ''
        self.send_zip_status = True

    def deployment_start(self, module):
        for i in module:
            self.deployment_create(i)
        return

    #根据版本获取对应模块并复制到相关目录
    def deployment_create(self, onemodule):
        zcell_git_name = self.Equipment.get('Equipment1',onemodule["modulename"])
        zcell_git_file1 = self.git_file
        zcell_git_file2 = os.path.join(zcell_git_file1, zcell_git_name)
        file = self.deployment_file
        self.module_file = os.path.join(file, onemodule["filename"])
        try:
            os.mkdir(self.module_file)
            repo = Repo(zcell_git_file2)
            repo.git.checkout(onemodule["version"])
            repo.close()
            a = os.listdir(zcell_git_file2)
            for i in a:
                b = os.path.join(zcell_git_file2, i)
                c = os.path.join(self.module_file,'Plugin')
                if i == 'Plugin':
                    shutil.copytree(b,c)
                elif i != '.git' and i != 'README.md':
                    shutil.copy(b,self.module_file)
                else:
                    pass
            self.deployment_write(onemodule["configuration"])
            self.deployment_zip()
        except BaseException as b:  # 所有异常的基类
            print('deployment_create str(e):\t\t', str(b))  # 简单
            print('deployment_create repr(e):\t', repr(b))  # 较简单
            print('deployment_create traceback.print_exc(): %s' % traceback.print_exc())  # 最详细
            os._exit(1)
        except:
            print('deployment_create traceback.print_exc(): %s' % traceback.print_exc())  # 最详细
            os._exit(1)
        return

    #修改对于模块中的配置
    def deployment_write(self, writefile):
        try:
            for file in writefile:
                other_config = myconf()
                other_file = os.path.join(self.module_file,file[0])
                other_config.read(other_file, encoding='gbk')
                for i in file[2].split('|'):
                    k,v = i.split('=')
                    other_config.set(file[1],k,v)
                fh = open(other_file,"w", encoding='gbk')
                other_config.write(fh)
                fh.close()
            exe_name = self.module_file.split('/').pop() + '.exe'
            lists = os.listdir(self.module_file)
            for item in lists:
                if item.endswith('exe'):
                    old_exe_file = os.path.join(self.module_file, item)
                    new_exe_file = os.path.join(self.module_file, exe_name)
                    shutil.move(old_exe_file, new_exe_file)
        except BaseException as b:  # 所有异常的基类
            print('deployment_write str(e):\t\t', str(b))  # 简单
            print('deployment_write repr(e):\t', repr(b))  # 较简单
            print('deployment_write traceback.print_exc(): %s' % traceback.print_exc())  # 最详细
            os._exit(1)
        except:
            print('deployment_write traceback.print_exc(): %s' % traceback.print_exc())  # 最详细
            os._exit(1)
        return

    #对模块进行压缩
    def deployment_zip(self):
        try:
            f = self.module_file + '.zip'
            pre_len = len(self.module_file)
            zipf = zipfile.ZipFile(f, 'w')
            for parent, dirnames, filenames in os.walk(self.module_file):
                for filename in filenames:
                    pathfile = os.path.join(parent, filename)
                    arcname = pathfile[pre_len:].strip(os.path.sep)
                    zipf.write(pathfile, arcname, compress_type=zipfile.ZIP_DEFLATED)
            zipf.close()
        except BaseException as b:  # 所有异常的基类
            print('deployment_zip str(e):\t\t', str(b))  # 简单
            print('deployment_zip repr(e):\t', repr(b))  # 较简单
            print('deployment_zip traceback.print_exc(): %s' % traceback.print_exc())  # 最详细
            os._exit(1)
        except:
            print('deployment_zip traceback.print_exc(): %s' % traceback.print_exc())  # 最详细
            os._exit(1)
        return

    #广播需要更新的模块
    def pub_zcell_all(self,zcell_list):
        pub_socket = context.socket(zmq.PUB)
        pub_port = self.config.get('ports','d_pub_port')
        pub_socket.bind("tcp://*:%s" % pub_port)
        sleep_time = 1
        # pza_poll = zmq.Poller()
        # pza_poll.register(pub_socket, zmq.POLLIN)
        while self.send_zip_status:
            # pza_socks = dict(pza_poll.poll(60000))
            # if pza_socks.get(pub_socket) == zmq.POLLIN:
            for i in zcell_list:
                for k,v in i.items():
                    msg = k + "|" + str(v)
                    print("->", msg)
                    pub_socket.send_string(msg)
            time.sleep(sleep_time)
            sleep_time += 1
            # else:
            #     print('广播通知较长时间无返回，程序结束')
            #     os._exit(2)
        pub_socket.close()
        print('已经通知到相关zcell，广播结束')
        return

    #和发送的类交互
    def contact_zip(self, module):
        try:
            deployment_list = []
            for i in module:
                deployment_list.append(i["filename"])
            print(deployment_list)
            already_deployment_list = []
            socket_port = self.config.get('ports','d_rep_port')
            while self.send_zip_status:
                print('开始接受消息')
                thread_socket = context.socket(zmq.REP)
                thread_socket.bind("tcp://*:%s" % socket_port)
                lists = thread_socket.recv_string()
                thread_socket.close()
                for i in eval(lists):
                    already_deployment_list.append(i)
                not_deployment_list = [item for item in deployment_list if item not in already_deployment_list]
                error_deployment_list = [item for item in already_deployment_list if item not in deployment_list]
                print(not_deployment_list,'============')
                print(already_deployment_list,'=============')
                if len(not_deployment_list) == 0:
                    print('已经完成更新，关闭所有线程')
                    serv.shutdown()
                    serv.server_close()
                    self.send_zip_status = False

                elif len(error_deployment_list) != 0:
                    print('无法匹配到对应的模块名称，程序结束')
                    serv.shutdown()
                    serv.server_close()
                    self.send_zip_status = False
                    os._exit(2)
        except BaseException as b:  # 所有异常的基类
            print('contact_zip str(e):\t\t', str(b))  # 简单
            print('contact_zip repr(e):\t', repr(b))  # 较简单
            print('contact_zip traceback.print_exc(): %s' % traceback.print_exc())  # 最详细
            os._exit(1)
        except:
            print('contact_zip traceback.print_exc(): %s' % traceback.print_exc())  # 最详细
            os._exit(1)
        return

    #开启socketserver
    def deployment_zip_send(self):
        #NWORKERS = 1
        socket_port = int(self.config.get('deployment','socket_port'))
        global serv
        serv = TCPServer(('', socket_port), DEHandler)
        #for n in range(NWORKERS):
            #t = threading.Thread(target=serv.serve_forever)
            #t.daemon = True
            #t.start()
        print('=================1')
        serv.serve_forever(poll_interval=0.5)
        print('=======================')

    #开启各服务
    def deployment_threading(self, module):
        zcell_all_list = []
        zcell_one_json = {}
        global context
        context = zmq.Context()
        try:
            for i in module:
                try:
                    one_list = zcell_one_json[i["zcellname"]]
                    one_list.append(i["filename"])
                except:
                    zcell_one_json[i["zcellname"]] = []
                    one_list = zcell_one_json[i["zcellname"]]
                    one_list.append(i["filename"])
                try:
                    zcell_all_list.index(zcell_one_json)
                except:
                    zcell_all_list.append(zcell_one_json)

            t2 = threading.Thread(target=self.deployment_zip_send)
            t2.start()
            t1 = threading.Thread(target=self.deployment_start, args=(module,))
            t1.start()
            t1.join()
            t3 = threading.Thread(target=self.pub_zcell_all, args=(zcell_all_list,))
            t4 = threading.Thread(target=self.contact_zip, args=(module, ))
            t3.start()
            t4.start()
            t4.join()
            context.destroy()
        except BaseException as b:  # 所有异常的基类
            print('deployment_threading str(e):\t\t', str(b))  # 简单
            print('deployment_threading repr(e):\t', repr(b))  # 较简单
            print('deployment_threading traceback.print_exc(): %s' % traceback.print_exc())  # 最详细
            os._exit(1)
        except:
            print('deployment_threading traceback.print_exc(): %s' % traceback.print_exc())  # 最详细
            os._exit(1)
        return
